#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <functional>
#include <future>
#include <atomic>
#include<unistd.h>
using func_t = std::function<void()>;

class ThreadPool
{
public:
    ThreadPool(int threadnum = 5)
        : _threadnum(threadnum), _stop(true)
    {
        // 创建线程
        _works.resize(_threadnum);
    }

    void Start()
    {
        _stop = false;
        for (int i = 0; i < _threadnum; i++)
        {
            _works[i] = std::thread(&ThreadPool::ThreadRountinue, this);
        }
    }

    void ThreadRountinue()
    {
        // 主要做的是取数据
        while (!_stop)
        {
            std::vector<func_t> tmp_tasks;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _cv.wait(lock, [this]()
                         { return _stop || !_tasks.empty(); });
                // 有数据了，交换线程池
                tmp_tasks.swap(_tasks);
            }
            for (auto &f : tmp_tasks)
            {
                f();
            }
        }
    }

    ~ThreadPool()
    {
        Stop();
    }

    // 用户传入的是函数，包装成异步任务,通过lanbda生成匿名对象，放到任务池中
    template <typename F, typename... Args>
    auto Push(const F &&f, Args &&...args) -> std::future<decltype(f(args...))>
    {
        using return_type = decltype(f(args...));
        auto fun = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
        // 包装异步任务
        auto ptask = std::make_shared<std::packaged_task<return_type()>>(fun);
        // 建立同步关系
        std::future<return_type> fu =ptask->get_future();
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _tasks.push_back([ptask]()
                             { (*ptask)(); });

            _cv.notify_one();
        }
        return fu;
    }

    void Stop()
    {
        if (_stop)
            return;
        _stop = true;
        _cv.notify_all();
        for (auto &thr : _works)
        {
            thr.join();
        }
        std::cout << "完成所有线程的清理工作" << std::endl;
    }

private:
    std::atomic<bool> _stop;
    int _threadnum;
    std::vector<func_t> _tasks;
    std::mutex _mutex;
    std::condition_variable _cv;
    std::vector<std::thread> _works;
};
int add(int a,int b){
    return a+b;
}

int main(){
    ThreadPool pool;
    pool.Start();
    for(int i=0;i<100;i++){
        std::future<int> fu=pool.Push(add,10,i);
        std::cout<<"10 + "<<i<<" = "<<fu.get()<<std::endl;
    }
    sleep(1);
    return 0;
}